<?php

session_start();

/**********************************************
error routines
**********************************************/
function terminal_error($err) {
 echo "<h1>A terminal error has occurred</h1>";
 echo $err;
 exit;
}
function nonterminal_error($err) {
 echo "<h1>A non terminal error has occurred</h1>";
 echo $err;
}

function sqlreadarray($stmt) {
 $dblink = getconn();
 $results = array();
 $result = mysqli_query($dblink,$stmt);
 if($result) {
  while($row = mysqli_fetch_array($result,MYSQLI_NUM)) {
   $results[] = $row;
  }
 } else {
  xd("Failed ".mysqli_error($dblink));
 }
 mysqli_close($dblink);
 return $results;
}

function sqlmultiquery($stmt) {
 $dblink = getconn();
 $success = true;
 $i = 0;

 if(mysqli_multi_query($dblink,$stmt)) {
   do { $i++; } 
    while($dblink->next_result());
  } else {
   nonterminal_error("E04: ".mysqli_error($dblink)."at line $i \n".$stmt);
   $success = false;
  }
  mysqli_close($dblink);
  return $success;
 }

function sqlreadarrayincmeta($stmt) {
 $dblink = getconn();
 $results = "";
 $result = mysqli_query($dblink,$stmt);
 $metadata = mysqli_fetch_fields($result);

 if($result) {
  while($row = mysqli_fetch_array($result,MYSQLI_NUM)) {
   $results[] = $row;
  }
 }
 mysqli_close($dblink);
 return array($results,$metadata);
}

function encrypt($word) {
 // Reversible encryption
 return base64_encode(strrev($word));
}

function decrypt($word) {
 return strrev(base64_decode($word));
}

function sqlreadassoc($stmt) {
 $dblink = getconn();
 $results = array();
 $result = mysqli_query($dblink,$stmt);
 if($result) {
  while($row = mysqli_fetch_assoc($result)) {
   $results[] = $row;
  }
 }
 mysqli_close($dblink);
 return $results;
}

function sqlreadkeyarray($stmt) {
 // Assumes unique id in the first column
 $dblink = getconn();
 $results = array();
 $result = mysqli_query($dblink,$stmt);
 if($result) {
  while($row = mysqli_fetch_array($result,MYSQLI_NUM)) {
   $results[$row[0]] = $row;
  }
 }
 mysqli_close($dblink);
 return $results;
}


function sqlreadkeyarrayconsol($stmt) {
 //Doesn't assume unique id in the first column
 $dblink = getconn();
 $results = array();
 $result = mysqli_query($dblink,$stmt);
 if($result) {
  while($row = mysqli_fetch_array($result,MYSQLI_NUM)) {
   $results[$row[0]][] = $row;
  }
 }
 mysqli_close($dblink);
 return $results;

}

function sqlread($stmt) {
 $dblink = getconn();
 $result = mysqli_query($dblink,$stmt);
 if($result) {
  $row = mysqli_fetch_array($result,MYSQLI_NUM);
 } else {
  $row = "";
 }
 mysqli_close($dblink);
 return $row;
}

function sqlexec($stmt) {
 $dblink = getconn();
 $thread_id = mysqli_thread_id($dblink);
 $result = mysqli_query($dblink,$stmt);
 if($result !== false) {
  //  mysqli_free_result($result);
  $rows_affected = mysqli_affected_rows($dblink);
  mysqli_close($dblink);
 } else {
  print_r(mysqli_error($dblink));
  mysqli_close($dblink);
 }
 // mysqli_kill($dblink,$thread_id);
 return $result;
}

function sqlexeccount($stmt) {
 $dblink = getconn();
 $thread_id = mysqli_thread_id($dblink);
 $result = mysqli_query($dblink,$stmt);
 if($result !== false) {
  $rows_affected = mysqli_affected_rows($dblink);
  mysqli_close($dblink);
 } else {
  print_r(mysqli_error($dblink));
  $rows_affected = 0;
  mysqli_close($dblink);
 }
 return array($result,$rows_affected);
}

function freaditem($table,$itemid) {
 $dblink = getconn();
 $table = mysqli_real_escape_string($dblink,$table);
 $itemid = mysqli_real_escape_string($dblink,$itemid);
 $stmt = "select * from $table where itemid = '$itemid' and strcmp(itemid,'$itemid') = 0";
 $result = mysqli_query($dblink,$stmt);
 if($result) {
  $row = mysqli_fetch_array($result,MYSQLI_NUM);
 } else {
  $row = array();
 }
 mysqli_close($dblink);
 return $row;
}

function freadfield($table,$itemid,$fname) {
 $dblink = getconn();
 $table = mysqli_real_escape_string($dblink,$table);
 $itemid = mysqli_real_escape_string($dblink,$itemid);
 $fname = mysqli_real_escape_string($dblink,$fname);
 $stmt = "select $fname from $table where itemid = '$itemid' and strcmp(itemid,'$itemid') = 0";
 $result = mysqli_query($dblink,$stmt);
 if($result) {
  $row = mysqli_fetch_array($result,MYSQLI_NUM);
  $ans = @$row[0];
 } else {
  $row = "";
  $ans = "";
 }
 mysqli_close($dblink);
 return $ans;
}

/**********************************************
date management functions
all internal dates and times are held as iso
**********************************************/

function isotoout($indate,$time = 0) {
 $dtonly = split(" ",$indate);
 $bits = split("-",$dtonly[0]);
 $rev = array_reverse($bits);
 $ans = join("-",$rev);
 if($time == 1) {
  $ans = $ans." ".$dtonly[1];
 }
 return $ans;
}

function dtoiso($indate = "") {
 // Does its best with user input. Returns false if it fails
 // Otherwise something suitable for MySQL.
 // Can be used for validation
 $indate = str_replace("/","-",$indate);
 $arr = split("-",$indate);
 $ans = '';
 if(sizeof($arr) == 2) {
  $arr[2] = date("Y");
 }
 if(sizeof($arr) == 3) {
  $y = $arr[2];
  if($y < 100) {
   $y = $y + 2000;
   $arr[2] = $y;
  }
  if(checkdate($arr[1],$arr[0],$arr[2])) {
   return sprintf("%02d",$arr[2])."-".sprintf("%02d",$arr[1])."-".sprintf("%02d",$arr[0]);
  } else {
   return false;
  }
 } else {
  return false;
 }
}

function datediff($isodateto,$isodatefrom = '') {
 // Assume dates are valid. isodatefrom can be left blank to default to today
 if($isodatefrom == '') {
  $isodatefrom = date("Y-m-d");
 }
 $to = explode('-',$isodateto);
 $from = explode('-',$isodatefrom);
 $ans = gregoriantojd($to[1],$to[2],$to[0]) - gregoriantojd($from[1],$from[2],$from[0]);
 return $ans;
}

/*****************************************************
* Connection functions
*****************************************************/
function getconn() {
 // Username, password, default databaee
 // if ($sname = @$_SESSION['schema']) {
 if($sname = 'liftmate') {
  $dblink = mysqli_connect("127.0.0.1","root","",$sname);
  if(!$dblink) {
   terminal_error("E01 : Serious connect err ");
   return false;
  } else {
   return $dblink;
  }
 } else {
  terminal_error("EO1 : No schema identified");
 }
}

function getcounter($type,$section) {
 $dblink = getconn();
 $comm = "call uniqueid('".$type."','".$section."')";
 $result = mysqli_query($dblink,$comm);
 if(!$result)
  terminal_error("E02 : Serious counters error");
 $row = mysqli_fetch_array($result);
 if(!$row)
  terminal_error("E03 : Missing counters error ".$type." ".$section);
 mysqli_close($dblink);
 return $row[0];
 /*
 for mysql:
 Needs mysql 5.0 or later
 CREATE DEFINER=`root`@`localhost` PROCEDURE `uniqueid`(doctype char(3),unit char(4))
 BEGIN
 start transaction ;
 select concat(prefix,cnt) from counters where doctype = counters.doctype and unit = counters.unit for update;
 update counters set cnt=cnt+1 where doctype = counters.doctype and unit=counters.unit      ;
 commit;
 END
 create table counters doctype chsr(3) , unit mediumint(9), prefix char(10)< cnt mediumint(9)
 */
}
/*****************************************************
* Authentication functions
*****************************************************/
function logauth() {
 $uid = @$_SESSION['user'];
 $req = preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/','',print_r($_SERVER,1));
 $req = str_replace("'",'',$req);
 $sql = "insert into accesslog values ('".date("Y-m-d H:i:s")."','".$uid."','".$req."')";
 sqlexec($sql);
}

function authenticate($prompt = true) {
 if(isset($_SESSION['user']))
  return $_SESSION['user'];

 if(isset($_REQUEST["userid"]) && isset($_REQUEST["password"])) {
  $userid = $_REQUEST['userid'];
  $password = $_REQUEST['password'];
 } elseif(isset($_COOKIE["_u"])) {
  $s = explode('|',$_COOKIE["_u"]);
  $userid = decrypt(@$s[0]);
  $password = @$s[1];
 } else {
  $userid = '';
  $password = '';
 }

 if(strlen($userid) > 0 && strlen($password) > 0) {
  if($userid = authenticatedb($userid,$password)) {
   if(isset($_REQUEST["cookie"])) {
    $cookieword = md5($userid.time());
    if(setcookie("_u",encrypt($userid)."|".$cookieword,time() + 60 * 60 * 24 * 30)) {
     sqlexec("update registereduser set confirmcode = '$cookieword'");
    }
   } else {
    setcookie("_u","",time() - 3600);
   }
   return $userid;
  }
 }

 if($prompt) {
  include 'showlogin.php';
  exit;
 } else {
  return false;
 }
}


function authorise($group) {
 // actively tries to authenticate the user
 authenticate(1);
 $groups = @$_SESSION["groups"];
 if(isset($groups[$group]))
  return true;
 if(isset($groups["ALL"]))
  return true;
 if($group === @$_SESSION['schema'])
  return true;
 include $_SERVER['DOCUMENT_ROOT'].'/autherr.php';
 exit;
}

function isauthorised($group) {
 // Passively confirms whether user is currently authorised
 $groups = @$_SESSION["groups"];
 if(isset($groups[$group]))
  return true;
 if($group === @$_SESSION['schema'])
  return true;
 if(isset($groups['ALL']))
  return true;
 return false;
}

function authenticatedb($userid,$password) {
 // Returns the userid and schema if valid. otherwise blank
 $dblink = getconn();
 $success = false;
 if($password !== "") {
  $userid = mysqli_real_escape_string($dblink,$userid);
  $password = mysqli_real_escape_string($dblink,$password);
  $stmt = "select registereduser.itemid,schemaname,grp from registereduser,registereduserline ";
  $stmt .= " where registereduser.itemid = registereduserline.itemid ";
  $stmt .= " and registereduser.name = '$userid'";
  $stmt .= " and (registereduser.password = md5('$password') or registereduser.confirmcode = '$password') ";
  if($result = mysqli_query($dblink,$stmt)) {
   $groups = "";
   while($row = mysqli_fetch_array($result,MYSQLI_NUM)) {
    $userid = $row[0];
    $schema = $row[1];
    $groups[$row[2]] = 1;
   }
   if($groups != '') {
    $_SESSION['user'] = $userid;
    $_SESSION['schema'] = $schema;
    $_SESSION['groups'] = $groups;
    $success = $userid;
   }
  }
 }

 mysqli_close($dblink);
 return $success;
}

function authenticatetext($userid,$password) {
 // Tries against a text file passwd.txt
 // form = userid/password in MD5
 // This will always be an admin user with ALL privileges
 $lines = @file("passwd.txt");
 if($lines) {
  foreach($lines as $count => $line) {
   list($u,$p) = @explode('/',$line);
   if($u == $userid) {
    if(md5($password) == $p) {
     return $userid;
    }
   }
  }
 }
 return "";
}

function micro_time() {
 $timearray = explode(" ",microtime());
 return ($timearray[1] + substr($timearray[0],0,3));
}


/*********************************************************************
head class for single dimensional data rows
*********************************************************************/
abstract class obj {

 public $lastsearchresults = "";
 public $lastsearch = "";
 public $lastsearchheader = "<tr><td>Id</td><td>Name</td></tr>";
 public $header = "";
 public $atts = 0;
 protected $table = "";
 public $metadata = "";
 protected $maintainhist = false;
 public $valid = false;
 public $valids = "";
 public $refs = "";
 public $lists = "";
 public $help = "";
 public $origheader;
 public $origlines;
 public $disabled = '';
 public $reltable = array();
 public $reltableline = array();

 function confirmfiled($itemid = null) {
  echo "<br><br>";
  echo "<body>";
  echo "<h1>$itemid Filed as requested</h1>";
  echo "<form>";
  echo "<input class=bt accesskey=C type=submit name=sub value='Continue'>";
  echo "</form>";
 }
 function showfail() {
  echo "<br><br>";
  echo "<body onload='document.form.sub.focus()'>";
  echo "<h1>Click to return to document</h1>";
  echo "<form name=form>";
  echo "<input accesskey=C class=bt type=submit name=sub value=Continue>";
  echo "</form>";
 }
 function selectlist($condition) {
  // Last search cached for speed.
  if($condition == $this->lastsearch) {
   return $this->lastsearchresults;
  } else {
   $stmt = "select itemid,name from ".$this->table;
   $words = explode(" ",$condition);
   if($condition !== "" and $condition !== "ALL") {
    if(sizeof($words) > 1) {
     $stmt .= " where name like '%$words[0]%'";
     for($i = 1; $i < sizeof($words); $i++) {
      $stmt .= " and name like '%$words[$i]%'";
     }
    } else {
     $stmt .= " where name like '%$condition%' or itemid like '%$condition%'";
    }
   }
   $stmt .= " order by editdate desc limit 1000";
   $ans = sqlreadarray($stmt);
   $this->lastsearchresults = $ans;
   $this->lastsearch = $condition;
   return $ans;
  }
 }

 function selectlisth($table,$condition,$fn,$addnothing = true) {
  if(is_array($table)) {
   $arr = $table;
   $addnothing = false;
  } else {
   $stmt = "select itemid,name from ".$table;
   $words = explode(" ",$condition);
   if($condition !== "" and $condition !== "ALL") {
    if(sizeof($words > 0)) {
     $stmt .= " where name like '%$words[0]%'";
     for($i = 1; $i < sizeof($words); $i++) {
      $stmt .= " and name like '%$words[$i]%'";
     }
    } else {
     $stmt .= " where name like '%$condition%'";
    }
   }
   $stmt .= " LIMIT 30";
   $arr = sqlreadarray($stmt);
  }
  $h = "";
  if($arr) {
   $chf = substr($fn,1);

   $h = "<select name=$fn>";
   foreach($arr as $item) {
    @($this->header[$chf] == $item[0])?$selected = "selected":$selected = "";
    $h .= "<option $selected value='$item[0]'>$item[0] - $item[1]</option>";
   }
   if($addnothing) {
    $h .= "<option value='[]'>Nothing in this list</option>";
   }
   $h .= "</select>";
  }
  return $h;
 }
 // Choose from a list
 function showchoose($head = "Choose From List",$prompt =
  "Enter to create a new item, or enter code, or enter text to reduce size of list",$choose = "Choose",$id = "") {
  (isset($_REQUEST["from"]))?$frm = $_REQUEST["from"]:$frm = 0;
  if($id == "") {
   (isset($_REQUEST["itemid"]))?$id = $_REQUEST["itemid"]:$id = "ALL";
  }
  echo "<h1>$head</h1>";
  echo "<body onload='document.form.itemid.focus()'>\n";
  echo "<form name='form' method=POST>";
  echo "<input type=hidden name=from value=0>\n";
  echo "<table>";
  echo "<tr>";
  echo "<td>$choose</td>";
  echo "<td>";
  echo "<input name=itemid>";
  echo "</td>";
  echo "<td>$prompt</td>";
  echo "</tr>";
  echo "</table>\n";
  echo "<input class=bt type=submit name=sub value=Enter>\n";
  echo "</form>\n";
  print "<p>";
  $list = $this->selectlist($id);
  if($list == "") {
   echo "<p>List empty when searching for $id. Type ALL to search for all items</p>";
  } else {
   $max = 7;
   $o = "";
   if($frm > 0) {
    $prevpage = $frm - $max;
    if($prevpage < 0)
     $prevpage = 0;
    echo "<a class=m2 href=?itemid=".urlencode($id)."&from=$prevpage>Previous page</a>";
   }
   $o .= "<table>";
   $o .= $this->lastsearchheader;
   for($i = $frm; $i < ($max + $frm) && $i < sizeof($list); $i++) {
    $value = $list[$i];
    $o .= "<tr>";
    $o .= "<td><a class=m1 href=?itemid={$value[0]}>{$value[0]}</a></td>";
    for($j = 1; $j < sizeof($value); $j++) {
     $o .= "<td>{$value[$j]}</td>";
    }
    $o .= "</tr>\n";
   }
   $o .= "</table>";
   echo $o;
   if($i < sizeof($list)) {
    echo "<a  class=m2  href=?itemid=".urlencode($id)."&from=$i>More</a>";
   }
  }
 }

 function textbox($p,$name = null,$disabled = "") {
  if($disabled == "") {
   $dis = $this->disabled;
  } else {
   $dis = $disabled;
  }
  if($name == null)
   $name = ucwords($this->metadata[$p]->name);
  $o = "<tr>";
  $o .= "<td valign=top>".$name."</td>";
  $o .= "<td>";
  $o .= "<textarea $dis id='id".$name."' name=f$p cols=40 rows=5>";
  $o .= $this->header[$p];
  $o .= "</textarea>";
  $o .= "<em>".$this->valids[$p]."</em></td>";
  $o .= "</tr>";
  return $o;
 }

 function datebox($p,$name = null,$disabled = "") {
  if($disabled == "") {
   $dis = $this->disabled;
  } else {
   $dis = $disabled;
  }
  if($name == null)
   $name = ucwords($this->metadata[$p]->name);
  $dt = isotoout($this->header[$p]);
  $o = "<tr><td>$name</td><td>";
  $o .= "<input $disabled id=dot$p name=f$p size=10 maxlength=10 type=text value='$dt'>\n";
  if($dis != "disabled") {
   $dc = "showChooser(this, 'dot$p', 'chooserSpan', 2006, 2020, 'd-m-Y', false);";
   $o .= "<img src='images\calendar.gif' onclick=".'"'.$dc.'"'.">\n";
   $o .= "<div id='chooserSpan' class='dateChooser' style='display: none; visibility: hidden; width: 160px;'>\n";
   $o .= "</div>\n";
  }
  $o .= "<em>".$this->valids[$p]."</em></td>";
  $o .= "</tr>";
  return $o;
 }

 function imageget($p,$name = null,$disabled = "") {
  if($disabled == "") {
   $dis = $this->disabled;
  } else {
   $dis = $disabled;
  }
  if($name == null)
   $name = ucwords($this->metadata[$p]->name);
  $o = "<tr>";
  $o .= "<td>$name</td>";
  $o .= "<td><input id='f".$p."' type='file' name='f".$p."'>";
  $o .= "<em>".$this->valids[$p]."</em></td>";
  if($this->header[$p] != "") {
   $o .= "<td rowspan=50 valign=top><img src='../uploads/".$this->header[$p]."' width=200></td>";
  }
  $o .= "</tr>";
  return $o;
 }

 function lineimageget($p,$name = null,$disabled = "") {
  if($disabled == "") {
   $dis = $this->disabled;
  } else {
   $dis = $disabled;
  }
  if($name == null)
   $name = ucwords($this->metadata[$p]->name);
  $o = "<tr>";
  $o .= "<td>$name</td>";
  //	 $o .= '<a href="#" onclick="document.getElementById(\'fileID\').click(); return false;" /> Upload File</a>';
  //   $o .= '<input type="file" id="fileID" style="visibility: hidden;" />';
  $o .= "<td><input id='f".$p."' type='file' name='f".$p."'>";
  $o .= "<em>".$this->valids[$p]."</em></td>";
  if($this->currentline[$p] != "") {
   $o .= "<td rowspan=50 valign=top><img src='../uploads/".$this->currentline[$p]."' width=200></td>";
  }
  $o .= "</tr>";
  return $o;
 }

 function applyfield($p,$err = "Invalid",$relfile = null,$type = null,$notnull = true,$f = null) {

  if($f == null) {
   $f = @$_REQUEST["f$p"];
  }
  if($f === "" && $notnull && $this->header[$p] == "") {
   $this->valids[$p] = "Cannot leave this field blank";
   return;
  }


  if($f == $this->header[$p]) {
   // No change.
   return;
  }

  if($type == null) {
   $type = @$this->metadata[$p]->type;
  }
  if($relfile == null) {
   $relfile = @$this->reltable[$p];
  }

  if($type == 12 || $type == 246) {
   $notnull = true;
  }

  if($f !== null) {
   if($relfile != null) {
    $desc = freaditem($relfile,$f);
    if($desc == '') {
     $this->valids[$p] = $err;
     $this->lists[$p] = $this->selectlisth($relfile,$f,'f'.$p);
    } else {
     $this->header[$p] = $f;
     $this->refs[$p] = $desc[1];
     $this->lists[$p] = '';
    }
   } elseif($type == 10) {
    // Date.

    $a = dtoiso($f);
    if($a) {

     $diff = isotojd() - isotojd($a);
     if($diff > 3600 || $diff < -3600) {
      $this->valids[$p] = $err;
     } else {
      $this->header[$p] = $a;
     }
    } else {
     $this->valids[$p] = "Invalid date";
    }
    if($notnull && $a == "" && $this->valids[$p] = "") {
     $this->valids[$p] = "Cannot leave blank";
    }
   } elseif($type == 12) {
    // Time and date. In ISO9660
    if(preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/',$f)) {
     $this->valids[$p] = "";
     $this->header[$p] = $f;
    } else {
     $this->valids[$p] = "Must be an ISO Date YYYY-MM-DD HH:MM:SS. e.g 2013-12-31 23:59:59";
    }
    if($notnull && $a == "" && $this->valids[$p] = "") {
     $this->valids[$p] = "Cannot leave blank";
    }
   } elseif($type == 246 || $type == 3) {

    // NUMERIC
    $size = $this->metadata[$p]->length;
    $dec = $this->metadata[$p]->decimals;
    $len = $size - $dec;
    if(preg_match("/^-{0,1}[0-9]{0,$len}[.]{0,1}[0-9]{0,$dec}$/",$f)) {
     $this->header[$p] = $f;
    } else {
     $this->valids[$p] = $err;
    }
    if($notnull && $this->header[$p] == "" && $this->valids[$p] = "") {
     $this->valids[$p] = "Cannot leave blank";
    }

   } else {
    // text
    $size = $this->metadata[$p]->length;
    if(preg_match('/^[0-9a-z\r\n A-Z&+*\(\)\-\'\.\/]{0,'.$size.'}$/',$f)) {
     $this->header[$p] = $f;
    } else {
     $this->valids[$p] = "Please only use letters, numbers, spaces and symbols&* ";
    }
   }
  } else {
   //   $this->valids[$p] = "Expected field missing";
  }

 }

 function applyphoto($p) {
  if($current_image = @$_FILES["f$p"]['name']) {
   if(@$_FILES["f$p"]["error"] == 1) {
    $this->valids[$p] = "Error ".$_FILES['f7']["error"];
   } else {
    $extension = strtolower(substr(strrchr($current_image,'.'),1));
    if(($extension == "jpg" || $extension == "bmp")) {
     $time = date("fYhis");
     $new_image = $time.".".$extension;
     $destination = "uploads/".$new_image;
     $action = copy($_FILES["f$p"]['tmp_name'],$destination);
     createthumb("uploads/$new_image","uploads/thumbs/$new_image",200,200);
     if($action) {
      $this->header[$p] = $new_image;
     }

    } else {
     $this->valids[$p] = "Invalid extension";
    }
   }
  }
 }

 function htmlrow($p,$name = null,$disabled = "") {

  if($disabled == "") {
   $dis = $this->disabled;
  } else {
   $dis = $disabled;
  }
  if($name == null)
   $name = ucwords($this->metadata[$p]->name);
  $o = "<tr>";
  if(@$this->metadata[$p]->type == 10) {
   // 10 date
   $o .= $this->datebox($p,$name,$disabled);
  } else
   if(@$this->lists[$p] == "") {
    // No prelists
    if($this->metadata[$p]->length > 150) {
     $o .= $this->textbox($p,$name = null,$disabled = "");
    } else {
     $this->valids[$p] != ""?$style = 'err':$style = 'inp';
     $o .= "<td $style>".$name."</td>";
     $o .= "<td>";
     $o .= "<input class=$style $dis id='idf$p' name=f$p size=".min(45,$this->metadata[$p]->length)." maxlength=".max(45,$this->
      metadata[$p]->length).' value="'.$this->header[$p].'">';
     $o .= $this->refs[$p];
     $o .= "</td>";
     $o .= "<td>";
     $o .= $this->valids[$p];
     $o .= "</td>";
    }
   } else {
    // A list exists
    $o .= "<td>".$name."</td>";
    $o .= "<td>".$this->lists[$p]."</td>";
   }
   $o .= "</tr>\n";
  return $o;
 }

 function markedited() {
  $this->header[3] = date("Y-m-d H:i:s");
  $user = authenticate(0);
  $this->header[4] = $user['itemid'];
 }

 function unload() {
  unset($_SESSION[get_class($this)]);
 }


}

abstract class head extends obj {
 // Master table class for single dimensional records

 abstract function applyfromrequest(); // Must be overrridden
 // abstract function showform();

 function gettablename() {
  return $this->table;
 }

 function getmetadata() {
  if(1 == 0) {
   //  if (isset($_SESSION[$this->table."_METADATA"])) {
   $this->metadata = $_SESSION[$this->table."_METADATA"];
  } else {
   $dblink = getconn();

   $result = mysqli_query($dblink,"select * from $this->table where 1=0");
   if(!$result) {
    terminal_error("Missing table $this->table");
   }
   ;
   $this->metadata = mysqli_fetch_fields($result);
   $_SESSION[$this->table."_METADATA"] = $this->metadata;
   mysqli_close($dblink);
  }
  $this->atts = sizeof($this->metadata);
 }

 function deletedb() {
  // This is usually going to need to be overridden to give more meaningful
  // user feedback when referential integrity breached.
  $success = true;
  $dblink = getconn();
  $sql = "delete from $this->table where itemid = '{$this->header[0]}'";
  $ans = sqlexec($sql);
  if(!$ans) {
   $this->result = "E05: Unable to delete - likely this is being referred to by another table\n";
   $success = false;
  }
  ;
  if($success) {
   unset($_SESSION[$this->table]);
  }

  mysqli_close($dblink);
  return $success;
 }

 function confirmdeleted($itemid = null) {
  // To preserve integrity, you are almost always going to override this.
  echo "<br><br>";
  echo "<body onload='document.form.sub.focus()'>";
  echo "<h1>$itemid Deleted as requested</h1>";
  echo "<form>";
  echo "<input class=bt accesskey=C type=submit name=sub value='Continue'>";
  echo "</form>";
 }

 function createblank() {
  $this->header = array_fill(0,$this->atts,"");
  $this->header[2] = "0";
  $this->valids = array_fill(0,$this->atts,"");
  $this->lists = array_fill(0,$this->atts,"");
  $this->refs = array_fill(0,$this->atts,"");
 }


 function registerhelp() {
  $this->gethelp();
  $o = "";
  if($this->help) {
   $ecs = "";
   foreach($this->help as $rec) {
    $o .= "<span id=hlp{$rec[0]} class='hlp' >\n";
    $o .= $rec[1]."\n";
    $o .= "</span>\n";
    $ecs .= "addevents('{$rec[0]}');";
   }
   $o .= "<script>$ecs</script>";
  }
  return $o;
 }


 function gethelp() {
  return;
  // For speed - keep this in the user session
  $u = authenticate("0");
  $u[0]['showhelp'] = "Y";
  unset($_SESSION[$this->table."_HELP"]);
  if($u[0]['showhelp'] == "Y") {
   if(isset($_SESSION[$this->table."_HELP"])) {
    $this->help = $_SESSION[$this->table."_HELP"];
   } else {
    $stmt = "select fieldno,notes from helps where interface = '".$this->table."'";
    $result = sqlreadarray($stmt);
    if($result) {
     $this->help = $result;
     $_SESSION[$this->table."_HELP"] = $this->help;
    } else {
     $_SESSION[$this->table."_HELP"] = "";
     ;
    }
   }
  }
 }

 function readdb($itemid) {

  if($itemid == "ALL" || $itemid == "")
   return false;
  $ans = freaditem($this->table,$itemid);
  if($ans == "") {
   return false;
  } else {
   $this->header = $ans;
   $this->origheader = $ans;
   $this->applyrefs();
   $this->setdisabled();
   return true;
  }
 }

 function setdisabled() {
  $this->disabled = '';
 }

 function applyrefs() {
  $this->valids = array_fill(0,$this->atts,"");
  $this->lists = array_fill(0,$this->atts,"");
  $this->refs = array_fill(0,$this->atts,"");
  foreach($this->reltable as $id => $tablename) {
   $this->refs[$id] = freadfield($tablename,$this->header[$id],'name');
  }
 }

 function newcounter() {
  return $this->header[0];
 }

 function writedb() {

  $success = true;
  $dblink = getconn();
  foreach($this->header as $id => $item) {
   $this->header[$id] = mysqli_real_escape_string($dblink,$item);
  }
  $this->markedited();
  if($this->header[2] == "0") {
   $this->header[2] = 1;
   $this->header[0] = $this->newcounter();
   $stmt = $this->makeinsertsql();
  } else {
   $stmt = $this->makeupdatesql();
  }

  $this->result = mysqli_query($dblink,$stmt);
  if(!$this->result) {
   $this->result = "E04: ".mysqli_error($dblink)."\n".$stmt;
   nonterminal_error($this->result);
   $this->header[2] -= 1;
   $success = false;
  } else {
   if($dblink->insert_id) {
    $this->header[0] = $dblink->insert_id;
   }

   if($this->maintainhist) {
    $t = $this->table;
    $this->table = $this->table."_hist";
    $stmt = $this->makeinsertsql();

    $this->result = mysqli_query($dblink,$stmt);
    $this->table = $t;
   }
   $_SESSION["lastid"] = $this->header[0];
   unset($_SESSION[get_class($this)]);
   unset($_SESSION[$this->table]);
  }
  mysqli_close($dblink);
  return $success;
 }

 function unload() {
  unset($_SESSION[get_class($this)]);
 }

  function makeupsertsql() {
  $stmt = "insert into $this->table values (";
  for ($i = 0; $i < $this->atts - 1; $i++) {
   $stmt .= "'" . $this->header[$i] . "',";
  }
  $stmt .= "'" . $this->header[$this->atts - 1] . "')";
  $stmt .= "ON DUPLICATE KEY UPDATE ";
  for ($i = 1; $i < $this->atts - 1; $i++) {
   $stmt .= $this->metadata[$i]->name . " = '" . $this->header[$i] . "', ";
  }
  $stmt .= $this->metadata[$i]->name . " = '" . $this->header[$i] . "' ";
  return $stmt ;
  
 }

 function makeinsertsql() {
  $stmt = "insert into $this->table values (";
  for($i = 0; $i < $this->atts - 1; $i++) {
   $stmt .= "'".$this->header[$i]."',";
  }
  $stmt .= "'".$this->header[$this->atts - 1]."')";

  return $stmt;
 }

 function makeupdatesql() {
  $this->header['2'] += 1;
  $stmt = "update $this->table set ";
  for($i = 1; $i < $this->atts - 1; $i++) {
   $stmt .= $this->metadata[$i]->name." = '".$this->header[$i]."', ";
  }
  $stmt .= $this->metadata[$i]->name." = '".$this->header[$i]."' ";
  $stmt .= " where itemid = '".$this->header[0]."' ";
  return $stmt;
 }

 function showform() {
  $focalpoint = "f0";
  echo "<head>";
  echo "<script src='scripts/datechooser.js' type='text/javascript'></script>";
  echo SCRIPTS;
  //
  echo "</head>\n";
  echo "<body onload='document.form.".$focalpoint.".focus()'>";
  echo "<h1>Manage $this->table Items</h1>\n";
  echo "<form name=form method=POST>\n";
  echo "<input type=hidden name=res value=''>\n";
  echo "<table>";
  for($i = 0; $i < $this->atts; $i++) {
   if($i <> 2 && $i <> 3 && $i <> 4) {
    // Show a date in the locale
    $type = @$this->metadata[$i]->type;
    echo $this->htmlrow($i);
   }
  }
  echo "</table>\n";
  echo "<input class=bt accesskey=A type=submit name=sub value=Apply>\n";
  echo "<input class=bt accesskey=S type=submit name=sub value=Save>\n";
  echo "<input class=bt type=submit name=sub value=Delete>\n";
  echo "<button class=bt onclick=rest()><span>Restart</span></button>\n";

  echo "</form>";
  // set up help
  echo ($this->registerhelp());
 }

}

/*********************************************************************
2D Class for two-table objects. For example purchase orders, sales orders
porder, porderline
sorder, sorderline
*********************************************************************/
abstract class head2d extends obj {
 public $lineatts = 0;
 protected $linetable = "";

 public $linemetadata;
 public $linehelp = "";

 public $lines = array();
 public $linevalids;
 public $linerefs;
 public $linelists;

 public $currentline;
 public $currentlinevalids;
 public $currentlinerefs;
 public $currentlinelists;
 public $editline = -1;

 function createblank() {
  $this->header = array_fill(0,$this->atts,"");
  $this->header[2] = "0";
  $this->valids = array_fill(0,$this->atts,"");
  $this->lists = array_fill(0,$this->atts,"");
  $this->refs = array_fill(0,$this->atts,"");
  $this->linerefs = array(array_fill(0,$this->atts,""));

  $this->currentline = array_fill(0,$this->lineatts,"");
  $this->currentlinerefs = array_fill(0,$this->lineatts,"");
  $this->currentlinevalids = array_fill(0,$this->lineatts,"");
  $this->currentlinelists = array_fill(0,$this->lineatts,"");
  $this->editline = -1;
 }

 abstract function applyfromrequest(); // Must be overrridden
 abstract function showform();

 function gettablename() {
  return $this->table;
 }
 function getlinestablename() {
  return $this->linetable;
 }

 function calcgst($lines = null) {
  if($lines == null) {
   $lines = $this->lines;
  }
  $arr = sqlreadkeyarray("select * from gst");
  $customer = freaditem("customer",$this->header[5]);

  $goods = 0;
  $gst = 0;
  foreach((array )$lines as $line) {
   $rateid = $line[12];
   $rate = @$arr[$rateid][5];
   $linegoods = $line[4] * 100 * $line[3];
   $gst += floor($rate * $linegoods / 100 + .49) / 100;
   $goods += floor($linegoods) / 100;
  }
  return array($goods,$gst);
 }

 function registerhelp() {
  $hlp = (array )$this->gethelp(); // Also adds errors
  $o = "";
  $ecs = "";
  foreach($hlp as $id => $val) {
   $o .= "<span id=hlp$id class='hlp' >\n";
   $o .= $val."\n";
   $o .= "</span>\n";
   $ecs .= "addevents('$id'); ";
  }
  $o .= "<script>$ecs</script>";
  return $o;
 }

 function getmetadata() {
  //For speed - keep this in the user session
  if(isset($_SESSION[$this->table."_METADATA"])) {
   $this->metadata = $_SESSION[$this->table."_METADATA"];
  } else {
   $dblink = getconn();
   $result = mysqli_query($dblink,"select * from $this->table where 1=0");
   if(!$result) {
    terminal_error("Missing table $this->table");
   }
   ;
   $this->metadata = mysqli_fetch_fields($result);
   $_SESSION[$this->table."_METADATA"] = $this->metadata;
   mysqli_close($dblink);
  }

  $this->atts = sizeof($this->metadata);
  if(isset($_SESSION[$this->table."_LINEMETADATA"])) {
   $this->linemetadata = $_SESSION[$this->table."_LINEMETADATA"];
  } else {
   $dblink = getconn();
   $stmt = "select * from ".$this->linetable." where 1=0";
   $result = mysqli_query($dblink,$stmt);
   if(!$result) {
    terminal_error("Missing table ".$this->linetable);
   }
   ;
   $this->linemetadata = mysqli_fetch_fields($result);
   $_SESSION[$this->table."_LINEMETADATA"] = $this->linemetadata;
   mysqli_close($dblink);
  }

  $this->lineatts = sizeof($this->linemetadata);
 }

 function gethelp() {
  // For speed - keep this in the user session
  $u = authenticate("0");

  if($u[0] == "Y") {
   if(isset($_SESSION[$this->table."_HELP"])) {
    $this->help = $_SESSION[$this->table."_HELP"];
   } else {
    $stmt = "select fieldname,note from help where tablename = '".$this->table."'";
    $result = sqlreadarray($stmt);
    // Convert to id keyed array
    $ans = "";
    if($result) {
     foreach($result as $v)
      $ans[$v[0]] = $v[1];
    }
    if($ans) {
     $this->help = $ans;
     $_SESSION[$this->table."_HELP"] = $this->help;
    } else {
     $_SESSION[$this->table."_HELP"] = "";
     ;
    }
   }
  }
  $hlp = $this->help;
  // Add on any errors;
  foreach((array )$this->currentlinevalids as $no => $name) {
   if($name) {
    $hlp["l".$no] = $name;
   }
  }
  return $hlp;
 }

 function addline() {
  // Add a line
  // If the current line is valid
  if(every($this->currentlinevalids,'')) {
   $l = $this->currentline[1];
   $this->lines[$l] = $this->currentline;
   $this->linerefs[$l] = $this->currentlinerefs;
   $this->currentline = $this->defaultline();
   $this->currentlinerefs = array_fill(0,$this->lineatts,"");
   $this->currentlinelists = $this->currentlinerefs;
  }

 }
 function removeline() {
  // Unset if requested. Note that unset is slow
  (isset($_REQUEST['x']))?$x = $_REQUEST['x']:$x = -1;
  if(isset($this->lines[$x])) {
   unset($this->lines[$x]);
   unset($this->linerefs[$x]);
   // Removes blanks
   $this->lines = array_values($this->lines);
   $this->linerefs = array_values($this->linerefs);
   $this->currentline = $this->defaultline();
  }
 }
 function moveup() {
  $p = @($_REQUEST['moveup']);
  if($p > 0) {
   $tline = $this->lines[$p - 1];
   $this->lines[$p - 1] = $this->lines[$p];
   $this->lines[$p] = $tline;

   $tline = $this->linerefs[$p - 1];
   $this->linerefs[$p - 1] = $this->linerefs[$p];
   $this->linerefs[$p] = $tline;
  }
 }
 function editline() {
  // Edit a line
  // if the current line is valid or the current line equals the default line
  if(isset($_REQUEST['editline']) && (every($this->currentlinevalids,'') || $this->currentline == $this->defaultline())) {
   $e = $_REQUEST['editline'];
   if(isset($this->lines[$e])) {
    $this->currentline = $this->lines[$e];
    $this->currentline[1] = $e;
    $this->currentlinevalids = array_fill(0,$this->lineatts,'');
   }
  }
 }

 function lineapplyfield($l,$p,$err = "Invalid",$relfile = null,$type = null,$notnull = false,$f = null) {
  // $p = attribute number. $l = line number
  if($type == null) {
   $type = @$this->linemetadata[$p]->type;
  }
  if($relfile == null) {
   $relfile = @$this->linereltable[$p];
  }
  if($type == 12 || $type == 246) {
   $notnull = true;
  }

  $id = "l".$p."_".$l;
  if($f == null)
   $f = @$_REQUEST[$id];

  if($f !== null) {
   if($relfile != null) {
    $desc = freaditem($relfile,$f);
    if($desc == '') {
     $this->linevalids[$l][$p] = $err;
     if($f != "") {
      $this->linelists[$l][$p] = $this->selectlisth($relfile,$f,$id);
     }
    } else {
     $this->lines[$l][$p] = $f;
     $this->linerefs[$l][$p] = $desc[1];
     $this->linelists[$l][$p] = '';
    }
   } elseif($type == 12) {
    // Date.
    $a = dtoiso($f);
    if($a) {
     $diff = isotojd() - isotojd($a);
     if($diff > 3600 || $diff < -3600) {
      $this->linevalids[$l][$p] = $err;
     } else {
      $this->lines[$l][$p] = $a;
     }
    } else {
     $this->linevalids[$l][$p] = "Invalid date";
    }
   } elseif($type == 246 || $type == 3) {

    // NUMERIC
    $size = $this->linemetadata[$p]->length;
    $dec = $this->linemetadata[$p]->decimals;
    $len = $size - $dec;
    if(preg_match("/^-{0,1}[0-9]{0,$len}[.]{0,1}[0-9]{0,$dec}$/",$f)) {
     $this->lines[$l][$p] = $f;
    } else {
     $this->linevalids[$l][$p] = $err;
    }
   } else {
    // text
    $size = $this->linemetadata[$p]->length;
    if(preg_match('/^[0-9a-z A-Z&+*\(\)\-\'\.\/]{0,'.$size.'}$/',$f)) {
     $this->lines[$l][$p] = $f;
    } else {
     $this->linevalids[$l][$p] = $err;
    }
   }
  } else {
   //   $this->valids[$p] = "Expected field missing";
  }
  if($f === "" && $notnull && $this->lines[$l][$p] == "") {
   $this->linevalids[$l][$p] = "Cannot leave this field blank";
  }
 }

 function lineapplycurrentfield($p,$err = "Invalid",$relfile = null,$type = null,$notnull = false) {
  // $p = attribute number. Applies to current line only
  if($type == null) {
   $type = @$this->linemetadata[$p]->type;
  }
  if($relfile == null) {
   $relfile = @$this->linereltable[$p];
  }
  if($type == 12 || $type == 246) {
   $notnull = true;
  }

  $f = @$_REQUEST["l$p"];
  if($f !== null) {
   if($relfile != null) {

    $desc = freaditem($relfile,$f);
    if($desc == '') {
     $this->currentlinevalids[$p] = $err;
     if($f != "") {
      $this->currentlinelists[$p] = $this->selectlisth($relfile,$f,'l'.$p);
     }
    } else {
     $this->currentline[$p] = $f;
     $this->currentlinerefs[$p] = $desc[1];
     $this->currentlinelists[$p] = '';
    }
   } elseif(@$this->linemetadata[$p]->length > 500) {

    // loose text note
    $size = $this->linemetadata[$p]->length;
    if(preg_match('/^[0-9a-z A-Z&+*\(\)\-\'\.\/]{0,'.$size.'}$/',$f)) {
     $this->currentline[$p] = $f;
    } else {
     $this->currentlinevalids[$p] = $err;
    }

   } elseif($type == 12) {
    // Date.
    $a = dtoiso($f);
    if($a) {
     $diff = isotojd() - isotojd($a);
     if($diff > 3600 || $diff < -3600) {
      $this->currentlinevalids[$p] = $err;
     } else {
      $this->currentlines[$p] = $a;
     }
    } else {
     $this->currentlinevalids[$p] = "Invalid date";
    }
   } elseif($type == 246 || $type == 3) {

    // NUMERIC
    $size = $this->linemetadata[$p]->length;
    $dec = $this->linemetadata[$p]->decimals;
    $len = $size - $dec;
    if(preg_match("/^-{0,1}[0-9]{0,$len}[.]{0,1}[0-9]{0,$dec}$/",$f)) {
     $this->currentline[$p] = $f;
    } else {
     $this->currentlinevalids[$p] = $err;
    }
   } else {
    // text
    $size = $this->linemetadata[$p]->length;
    if(preg_match('/^[0-9a-z A-Z&+*\(\)\-\'\.\/]{0,'.$size.'}$/',$f)) {
     $this->currentline[$p] = $f;
    } else {
     $this->currentlinevalids[$p] = $err;
    }
   }
  } else {
   //   $this->valids[$p] = "Expected field missing";
  }

 }


 function readdb($itemid) {
  if($itemid == "ALL" || $itemid == "")
   return false;
  $ans = freaditem($this->table,$itemid);
  if($ans == "") {
   return false;
  } else {
   $this->header = $ans;
   $this->origheader = $ans;
   $this->applyrefs();

   $ans = sqlreadarray("select * from $this->linetable where itemid='".$itemid."' order by seq");
   if($ans != "") {
    $this->lines = $ans;
    $this->origlines = $ans;
    $this->applylinerefs();
    $this->setdisabled();
   }
   $this->currentline = $this->defaultline();
   return true;
  }
 }

 function setdisabled() {
  $this->disabled = '';
 }

 function applyrefs() {
  $this->valids = array_fill(0,$this->atts,"");
  $this->lists = array_fill(0,$this->atts,"");
  $this->refs = array_fill(0,$this->atts,"");
  foreach($this->reltable as $id => $tablename) {
   $this->refs[$id] = freadfield($tablename,$this->header[$id],'name');
  }
 }

 function applylinerefs() {
  $this->linevalids = array_fill(0,$this->lineatts,"");
  $this->linelists = array_fill(0,$this->lineatts,"");
  //  $this->linerefs = array_fill(0,sizeof($this->lines),array_fill(0,$this->lineatts,""));
  $this->linerefs = array();
  // This is fairly innefficient. Override all if necessary.

  foreach($this->lines as $id => $li) {
   foreach($this->reltableline as $id2 => $tablename) {
    $this->linerefs[$id][$id2] = freadfield($tablename,$li[$id2],'name');
   }
  }
 }


 function defaultline() {
  $ans = array_fill(0,$this->lineatts,"");
  $this->currentline[1] = sizeof($this->lines);
  return $ans;
 }

 function newcounter() {
  return $this->header[0];
 }

 function writedb() {
  $success = true;
  $dblink = getconn();
  // get rid of any possible injection
  foreach($this->header as $id => $item) {
   $this->header[$id] = mysqli_real_escape_string($dblink,$item);
  }
  if(is_array($this->lines)) {
   foreach($this->lines as $id => $item) {
    foreach($item as $pos => $field) {
     $this->lines[$id][$pos] = mysqli_real_escape_string($dblink,$field);
    }
   }
  }

  // Add user info and edit date
  $this->header[3] = date("Y-m-d H:i:s");
  $this->header[4] = authenticate(0);
  if($this->header[4] = '')
   $this->header[4] = '0';
  // If inserting
  if($this->header[2] == "0") {
   $this->header[2] = 1;
   $this->header[0] = $this->newcounter();
   $stmt = $this->makeinsertsql();
  } else {
   // editing
   $stmt = $this->makeupdatesql();
   if($this->maintainhist) {
    $t = $this->table;
    $t2 = $this->linetable;
    $this->table = $this->table."_hist";
    $this->linetable = $this->linetable."_hist";
    $stmt .= ";\n".$this->makeinsertsql();
    $this->table = $t;
    $this->linetable = $t2;
   }
  }
  // execute query
  if(mysqli_multi_query($dblink,$stmt)) {
   $i = 0;
   do {
    $i++;
   } while($dblink->next_result());
  } else {
   $this->result = false;
   $this->result = "E04: ".mysqli_error($dblink)."at line $i \n".$stmt;
   nonterminal_error($this->result);
   $success = false;
  }

  // deal with results
  if($dblink->errno) {
   $success = false;
   $_SESSION["lastid"] = $this->header[0];
   unset($_SESSION[get_class($this)]);
   unset($_SESSION[$this->linetable]);
   unset($_SESSION[$this->table]);
  }

  mysqli_close($dblink);
  return $success;
 }

 function makeinsertsql() {

  $multisql = "";
  // Do the lines first

  if(sizeof($this->lines) > 0) {
   $sql = "insert into $this->linetable values ";
   for($l = 0; $l < sizeof($this->lines); $l++) {
    $this->lines[$l][1] = $l;
    $sql .= "('".$this->header[0]."'";
    for($i = 1; $i < $this->lineatts; $i++) {
     $sql .= ",'".$this->lines[$l][$i]."'";
    }
    $sql .= ")";
    if($l < sizeof($this->lines) - 1) {
     $sql .= ",";
    }
   }
   $multisql .= $sql.";\n";
  }
  // Then do the header
  $multisql .= "insert into $this->table values (";
  for($i = 0; $i < $this->atts - 1; $i++) {
   $multisql .= "'".$this->header[$i]."',";
  }
  $multisql .= "'".$this->header[$this->atts - 1]."') ;\n";
  return $multisql;
 }

 function makeupdatesql() {
  // header
  $this->header['2'] += 1;
  $multisql = "update $this->table set ";
  for($i = 1; $i < $this->atts - 1; $i++) {
   $multisql .= $this->metadata[$i]->name." = '".$this->header[$i]."', ";
  }
  $multisql .= $this->metadata[$i]->name." = '".$this->header[$i]."' ";
  $multisql .= " where itemid = '".$this->header[0]."';\n";

  // Do the lines next. Note that this is theoretically inefficient. If one
  // line gets edited, the whole lot get scrapped and put in again.
  // Before overriding, here are some considerations:
  //  - Two deletes + one change + one insert may not be any quicker than 4 deletes+4 inserts
  //  - Line numbers change during edits.
  //  - Ensure you have a speed bottleneck in the database itself before going to the effort.
  //  - Also note syntax for the insert. Don't try to do the insert on separate lines - there is a
  //  - nasty bug in mysqli.

  $multisql .= "delete from $this->linetable where itemid = '".$this->header[0]."' ;";

  if(sizeof($this->lines) > 0) {
   $sql = "insert into $this->linetable values ";
   for($l = 0; $l < sizeof($this->lines); $l++) {
    $this->lines[$l][1] = $l;
    $sql .= "('".$this->header[0]."'";
    for($i = 1; $i < $this->lineatts; $i++) {
     $sql .= ",'".@$this->lines[$l][$i]."'";
    }
    $sql .= ")";
    if($l < sizeof($this->lines) - 1) {
     $sql .= ",";
    }
   }
   $multisql .= "\n".$sql;
  }
  return $multisql;
 }

 function localprint() {
  echo "<body onload='document.form.sub.focus(); window.print();'>";
  echo "<form name=form>";
  echo "<input name=sub class=bt type=submit value='Click to Continue'>";
  echo "</form>";
  echo "</body>";
 }

 function htmlline($p,$name = null,$disabled = "") {
  if($disabled == "") {
   $dis = $this->disabled;
  } else {
   $dis = $disabled;
  }
  if($name == null)
   $name = $this->linemetadata[$p]->name;
  $o = "<tr>";
  $o .= "<td>".$name."</td>";
  if($this->currentlinelists[$p] == "") {
   $o .= "<td>";
   $o .= "<input $dis id='id".$name."' name=l$p size=".min(45,$this->linemetadata[$p]->length)." maxlength=".$this->
    linemetadata[$p]->length.' value="'.$this->currentline[$p].'">';
   if(isset($this->currentlinerefs[$p])) {
    $o .= $this->currentlinerefs[$p];
   }
   $o .= "</td>";
  } else {
   $o .= "<td>".$this->currentlinelists[$p]."</td>";
  }

  $o .= "<td>".$this->currentlinevalids[$p]."</td>";
  $o .= "</tr>";
  return $o;
 }

 function linetextbox($p,$name = null,$disabled = "") {
  if($disabled == "") {
   $dis = $this->disabled;
  } else {
   $dis = $disabled;
  }
  if($name == null)
   $name = ucwords($this->linemetadata[$p]->name);
  $o = "<tr>";
  $o .= "<td valign=top>".$name."</td>";
  $o .= "<td>";
  $o .= "<textarea $dis id='idl".$name."' name=l$p cols=40 rows=5>";
  $o .= $this->currentline[$p];
  $o .= "</textarea>";
  $o .= "<em>".$this->currentlinevalids[$p]."</em></td>";
  $o .= "</tr>";
  return $o;
 }

 function applyphototoline($p) {
  if($current_image = @$_FILES["f$p"]['name']) {
   if(@$_FILES["f$p"]["error"] == 1) {
    $this->currentlinevalids[$p] = "Error ".$_FILES["f$p"]["error"];
   } else {
    $extension = strtolower(substr(strrchr($current_image,'.'),1));
    if(($extension == "jpg" || $extension == "bmp")) {
     $time = date("fYhis");
     $new_image = $time.".".$extension;
     $destination = "uploads/".$new_image;
     $action = copy($_FILES["f$p"]['tmp_name'],$destination);
     if($action) {
      createthumb("uploads/$new_image","uploads/thumbs/$new_image",200,200);
      $this->currentline[$p] = $new_image;
     }
    } else {
     $this->currentlinevalids[$p] = "Invalid extension";
    }
   }
  }
 }

}

/*********************************************************************
other
*********************************************************************/
function emailatt($att,$dest = 'mail@antonylawler.com') {
 $message = "PDF ATTACHED";
 $file = chunk_split(base64_encode($att));
 $num = md5(time());
 $headers = "From: Name<name@name.com>\r\n";
 $headers .= "MIME-Version: 1.0\r\n";
 $headers .= "Content-Type: multipart/mixed; ";
 $headers .= "boundary=".$num."\r\n";
 $headers .= "--$num\r\n";
 $headers .= "Content-Type: text/html; charset=iso-8859-1\r\n";
 $headers .= "Content-Transfer-Encoding: 8bit\r\n";
 $headers .= $message."\n";
 $headers .= "--".$num."\n";
 $headers .= "Content-Type:application/pdf ";
 $headers .= "name=name.pdf r\n";
 $headers .= "Content-Transfer-Encoding: base64\r\n";
 $headers .= "Content-Disposition: attachment; ";
 $headers .= "filename=pdffile.pdf \r\n\n";
 $headers .= "".$file."\r\n";
 $headers .= "--".$num."--";
 mail($dest,'pdf','body',$headers);
}

function generatepassword() {
 $password = "";
 $possible = "abcdfghjkmnpqrstvwxyz";
 for($i = 0; $i < 8; $i++) {
  $password .= substr($possible,mt_rand(0,strlen($possible) - 1),1);
 }
 return $password;
}

function tabtohtm($array,$options = "",$h = "") {
 if(strpos($options,"I") !== false) {
  // Invert
  $new = "";
  for($i = 0; $i < sizeof($array); $i++) {
   for($j = 0; $j < sizeof($array[$i]); $j++) {
    $new[$j][$i] = $array[$i][$j];
   }
  }
  $array = $new;
 }
 $o = "";
 if(strpos($options,"S") !== false) {
  $o .= '<html>';
  $o .= '<heading>';
  $o .= "<style>";
  $o .= "table {border-collapse:collapse;}";
  $o .= 'th {font-family:arial; font-size:12;background-color:#cccccc;  border:1px solid black;}';
  $o .= 'td {font-family:arial; font-size:12; border:1px solid black;}';
  $o .= 'p  {font-family:arial; font-size:11; color:black}';
  $o .= 'h1 {font-family:arial; font-size:20}';
  $o .= 'h2 {font-family:arial; font-size:16}';
  $o .= 'h3 {font-family:arial; font-size:14}';
  $o .= 'h4 {font-family:arial; font-size:14; color:#666666}';
  $o .= 'h5 {font-family:arial; font-size:16; color:blue}';
  $o .= 'li {font-family:arial; font-size:12}';
  $o .= '</style>';
  $o .= '</heading>';
  $o .= '<body>';
 }

 $o .= "<table>";
 $o .= $h;
 foreach($array as $id => $item) {
  $o .= "<tr>";
  foreach($item as $cell) {
   $o .= "<td>$cell</td>";
  }
  $o .= "</tr>";
 }
 $o .= "</table>";
 return $o;
}

function createthumb($name,$filename,$new_w,$new_h) {
 $system = explode('.',$name);
 if(preg_match('/jpg|jpeg/',$system[1]))
  $src_img = imagecreatefromjpeg($name);
 if(preg_match('/png/',$system[1]))
  $src_img = imagecreatefrompng($name);

 $old_x = imageSX($src_img);
 $old_y = imageSY($src_img);

 if($old_x > $old_y) {
  $thumb_w = $new_w;
  $thumb_h = $old_y * ($new_h / $old_x);
 }
 if($old_x < $old_y) {
  $thumb_w = $old_x * ($new_w / $old_y);
  $thumb_h = $new_h;
 }
 if($old_x == $old_y) {
  $thumb_w = $new_w;
  $thumb_h = $new_h;
 }

 $dst_img = ImageCreateTrueColor($thumb_w,$thumb_h);
 imagecopyresized($dst_img,$src_img,0,0,0,0,$thumb_w,$thumb_h,$old_x,$old_y);
 if(preg_match("/png/",$system[1])) {
  imagepng($dst_img,$filename);
 } else {
  imagejpeg($dst_img,$filename);
 }

 imagedestroy($dst_img);
 imagedestroy($src_img);
}

function validateemail($email) {
 if(eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$",$email)) {
  return true;
 } else {
  return false;
 }
}

function every($array,$value) {
 if(is_array($array)) {
  foreach($array as $id => $val) {
   if($val !== $value)
    return false;
  }
 } else {
  if($value == "") {
   return true;
  } else {
   return false;
  }
 }
 return true;
}

function iscurrency($instring) {
 $v1 = $instring * 100;
 $v2 = floor($v1 + .05);
 $v1 = $v1."";
 $v2 = $v2."";
 if($v1 == $v2 && $v1 * 1 !== 0) {
  return true;
 } else {
  return false;
 }
}
function validpassword($password) {
 $valid = true;
 if(strpos('"',$password))
  $valid = false;
 if(strpos("'",$password))
  $valid = false;
 if(strpos("/",$password))
  $valid = false;
 if(strpos("'",$password))
  $valid = false;
 if(strlen($password) < 4)
  $valid = false;
 return $valid;
}
function xd($x) {
 print "<pre>";
 print "\n\n\n\n\n\n\n\n";
 print_r($x);
}
function cururl() {
 $pageURL = 'http';
 if(@$_SERVER["HTTPS"] == "on") {
  $pageURL .= "s";
 }
 $pageURL .= "://";
 if($_SERVER["SERVER_PORT"] != "80") {
  $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
 } else {
  $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
 }
 return urlencode($pageURL);
}
define('SCRIPTS',"
  <script>
  function rest() {  
   if (document.form.res.value != 'restart') {
   if (confirm('Lose all changes - you sure ?')) {
    document.form.res.value='restart';
    document.form.submit();
   }   
   }
  }
  function submitform1(vl) {
   document.form.editline.value=vl;
   document.form.submit();
  }
  function submitform2(vl) {
   document.form.x.value=vl;
   document.form.submit();
  } 
  function submitform3(vl) {
   document.form.moveup.value=vl;
   document.form.submit();
  } 

  function addevents(elid) {
   obj = document.getElementById('id'+elid);
   if (obj) {
    if (document.addEventListener) {
     obj.addEventListener('focus',function() {document.getElementById('hlp'+elid).style.visibility='visible'} , false);
     obj.addEventListener('blur',function() {document.getElementById('hlp'+elid).style.visibility='hidden'} , false);
    } else {
     obj.attachEvent('onfocus',function() {document.getElementById('hlp'+elid).style.visibility='visible'});
     obj.attachEvent('onblur',function() {document.getElementById('hlp'+elid).style.visibility='hidden'});
    }
   } else {
    //  alert ('Cannot give help on ' + elid);
   }
  }
  
  function checkarrow(id) {
	 if (window.event) kc = window.event.keyCode 
	 bits = id.split('_');
	 if (kc == 38) {
			 t = bits[0] + '_' + (bits[1]*1-1).toString();
			 document.getElementById(t).focus();
			 document.getElementById(t).select();
	 }
	 if (kc == 40) {
	     // Try to move down
			 t = bits[0] + '_' + (bits[1]*1+1).toString();
			 document.getElementById(t).focus();
			 document.getElementById(t).select();
	 }
  }

  </script>
  ")

?>
